/*****************************************************************************
*
*  PROJECT:     Native Executive
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        NativeExecutive/CExecutiveManager.rwlock.cpp
*  PURPOSE:     Read/Write lock synchronization object
*  DEVELOPERS:  Martin Turski <quiret@gmx.de>
*
*  Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"

BEGIN_NATIVE_EXECUTIVE

// Native wrapped object.
struct CReadWriteLockNative : public CReadWriteLock
{
    AINLINE CReadWriteLockNative( readWriteLockEnv_t *lockEnv )
    {
        this->lockEnv = lockEnv;

        // The lock environment must be properly initialized.
    }

    AINLINE static size_t GetSize( readWriteLockEnv_t *lockEnv )
    {
        return ( sizeof(CReadWriteLockNative) + lockEnv->readWriteLockSize );
    }

    AINLINE static void Constructor( readWriteLockEnv_t *lockEnv, void *mem )
    {
        CReadWriteLockNative *nativeLock = new (mem) CReadWriteLockNative( lockEnv );

        void *lockMem = ( nativeLock + 1 );

        lockEnv->constructor( lockMem, lockEnv );
    }

    AINLINE static void Destructor( readWriteLockEnv_t *lockEnv, CReadWriteLockNative *lockImpl )
    {
        // Delete main lock.
        {
            void *main_lock_mem = ( lockImpl + 1 );

            lockEnv->destructor( main_lock_mem, lockEnv );
        }

        lockImpl->~CReadWriteLockNative();
    }

    AINLINE void EnterCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        lockEnv->enter_read( lockMem, lockEnv );
    }

    AINLINE void LeaveCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        lockEnv->leave_read( lockMem, lockEnv );
    }

    AINLINE void EnterCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        lockEnv->enter_write( lockMem, lockEnv );
    }

    AINLINE void LeaveCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        lockEnv->leave_write( lockMem, lockEnv );
    }

    AINLINE bool TryEnterCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        return lockEnv->try_enter_read( lockMem, lockEnv );
    }

    AINLINE bool TryEnterCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        return lockEnv->try_enter_write( lockMem, lockEnv );
    }

    readWriteLockEnv_t *lockEnv;
};

void CReadWriteLock::EnterCriticalReadRegion( void )
{
    ((CReadWriteLockNative*)this)->EnterCriticalReadRegionNative();
}

void CReadWriteLock::LeaveCriticalReadRegion( void )
{
    ((CReadWriteLockNative*)this)->LeaveCriticalReadRegionNative();
}

void CReadWriteLock::EnterCriticalWriteRegion( void )
{
    ((CReadWriteLockNative*)this)->EnterCriticalWriteRegionNative();
}

void CReadWriteLock::LeaveCriticalWriteRegion( void )
{
    ((CReadWriteLockNative*)this)->LeaveCriticalWriteRegionNative();
}

bool CReadWriteLock::TryEnterCriticalReadRegion( void )
{
    return ((CReadWriteLockNative*)this)->TryEnterCriticalReadRegionNative();
}

bool CReadWriteLock::TryEnterCriticalWriteRegion( void )
{
    return ((CReadWriteLockNative*)this)->TryEnterCriticalWriteRegionNative();
}

// Executive manager API.
CReadWriteLock* CExecutiveManager::CreateReadWriteLock( void )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    if ( !lockEnv->constructor )
        return NULL;

    size_t lockSize = CReadWriteLockNative::GetSize( lockEnv );

    void *mem = new char[ lockSize ];

    try
    {
        CReadWriteLockNative::Constructor( lockEnv, mem );
    }
    catch( ... )
    {
        delete mem;

        throw;
    }

    return (CReadWriteLock*)mem;
}

void CExecutiveManager::CloseReadWriteLock( CReadWriteLock *theLock )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    CReadWriteLockNative *lockImpl = (CReadWriteLockNative*)theLock;

    CReadWriteLockNative::Destructor( lockEnv, lockImpl );

    void *anon_mem = theLock;

    delete anon_mem;
}

size_t CExecutiveManager::GetReadWriteLockStructSize( void )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    return CReadWriteLockNative::GetSize( lockEnv );
}

CReadWriteLock* CExecutiveManager::CreatePlacedReadWriteLock( void *mem )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    // We lack a constructor then we do not support anything.
    if ( !lockEnv->constructor )
        return NULL;

    CReadWriteLockNative::Constructor( lockEnv, mem );

    return (CReadWriteLock*)mem;
}

void CExecutiveManager::ClosePlacedReadWriteLock( CReadWriteLock *placedLock )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    CReadWriteLockNative *lockImpl = (CReadWriteLockNative*)placedLock;

    CReadWriteLockNative::Destructor( lockEnv, lockImpl );
}

// Native wrapped object.
struct CReentrantReadWriteLockNative : public CReentrantReadWriteLock
{
    AINLINE CReentrantReadWriteLockNative( readWriteLockEnv_t *lockEnv )
    {
        this->lockEnv = lockEnv;

        // The lock environment must be properly initialized.
    }

    AINLINE static size_t GetSize( readWriteLockEnv_t *lockEnv )
    {
        return ( sizeof(CReentrantReadWriteLockNative) + lockEnv->rentReadWriteLockSize );
    }

    AINLINE static void Constructor( readWriteLockEnv_t *lockEnv, void *mem )
    {
        CReentrantReadWriteLockNative *nativeLock = new (mem) CReentrantReadWriteLockNative( lockEnv );

        void *lockMem = ( nativeLock + 1 );

        lockEnv->rent_constructor( lockMem, lockEnv );
    }

    AINLINE static void Destructor( readWriteLockEnv_t *lockEnv, CReentrantReadWriteLockNative *lockImpl )
    {
        // Delete main lock.
        {
            void *main_lock_mem = ( lockImpl + 1 );

            lockEnv->rent_destructor( main_lock_mem, lockEnv );
        }

        lockImpl->~CReentrantReadWriteLockNative();
    }

    AINLINE void EnterCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        this->lockEnv->rent_enter_read( lockMem, lockEnv );
    }

    AINLINE void LeaveCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        this->lockEnv->rent_leave_read( lockMem, lockEnv );
    }

    AINLINE void EnterCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        this->lockEnv->rent_enter_write( lockMem, lockEnv );
    }

    AINLINE void LeaveCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        this->lockEnv->rent_leave_read( lockMem, lockEnv );
    }

    AINLINE bool TryEnterCriticalReadRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        return this->lockEnv->rent_try_enter_read( lockMem, lockEnv );
    }

    AINLINE bool TryEnterCriticalWriteRegionNative( void )
    {
        void *lockMem = ( this + 1 );

        readWriteLockEnv_t *lockEnv = this->lockEnv;

        return this->lockEnv->rent_try_enter_write( lockMem, lockEnv );
    }

    readWriteLockEnv_t *lockEnv;
};

// Reentrant RW lock implementation.
void CReentrantReadWriteLock::EnterCriticalReadRegion( void )
{
    ((CReentrantReadWriteLockNative*)this)->EnterCriticalReadRegionNative();
}

void CReentrantReadWriteLock::LeaveCriticalReadRegion( void )
{
    ((CReentrantReadWriteLockNative*)this)->LeaveCriticalReadRegionNative();
}

void CReentrantReadWriteLock::EnterCriticalWriteRegion( void )
{
    ((CReentrantReadWriteLockNative*)this)->EnterCriticalWriteRegionNative();
}

void CReentrantReadWriteLock::LeaveCriticalWriteRegion( void )
{
    ((CReentrantReadWriteLockNative*)this)->LeaveCriticalWriteRegionNative();
}

// Executive manager API.
CReentrantReadWriteLock* CExecutiveManager::CreateReentrantReadWriteLock( void )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    // No constructor means no support.
    if ( !lockEnv->rent_destructor )
        return NULL;

    size_t lockSize = CReentrantReadWriteLockNative::GetSize( lockEnv );

    char *mem = new char[ lockSize ];

    try
    {
        CReentrantReadWriteLockNative::Constructor( lockEnv, mem );
    }
    catch( ... )
    {
        delete mem;

        throw;
    }

    return (CReentrantReadWriteLock*)mem;
}

void CExecutiveManager::CloseReentrantReadWriteLock( CReentrantReadWriteLock *theLock )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    CReentrantReadWriteLockNative *lockImpl = (CReentrantReadWriteLockNative*)theLock;

    CReentrantReadWriteLockNative::Destructor( lockEnv, lockImpl );

    void *anonMem = theLock;

    delete anonMem;
}

size_t CExecutiveManager::GetReentrantReadWriteLockStructSize( void )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    return CReentrantReadWriteLockNative::GetSize( lockEnv );
}

CReentrantReadWriteLock* CExecutiveManager::CreatePlacedReentrantReadWriteLock( void *mem )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    // If the constructor is not present, then we assume we have no locks of this type.
    if ( !lockEnv->rent_constructor )
        return NULL;

    CReentrantReadWriteLockNative::Constructor( lockEnv, mem );

    return (CReentrantReadWriteLock*)mem;
}

void CExecutiveManager::ClosePlacedReentrantReadWriteLock( CReentrantReadWriteLock *theLock )
{
    CExecutiveManagerNative *execMan = (CExecutiveManagerNative*)this;

    readWriteLockEnv_t *lockEnv = &execMan->readWriteLockEnv;

    CReentrantReadWriteLockNative *lockImpl = (CReentrantReadWriteLockNative*)theLock;

    CReentrantReadWriteLockNative::Destructor( lockEnv, lockImpl );
}

END_NATIVE_EXECUTIVE